package org.lmind.example.common.core.jpa;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

public class EntityManagerHelper {

	@PersistenceContext
	private EntityManager entityManager;

	public EntityManagerHelper() {
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
	
	public <T> List<T> query(Class<T> clazz, String jpql, int start, int limit, Object... params) {
		Query query = entityManager.createQuery(jpql);
		setParameter(query, start, limit, params);
		return getResultList(clazz, query);
	}
	
	public <T> List<T> query(Class<T> clazz, String jpql, int start, int limit, 
			Map<String, Object> params) {
		Query query = entityManager.createQuery(jpql);
		setParameter(query, start, limit, params);
		return getResultList(clazz, query);
	}

	public <T> List<T> query(Class<T> clazz, String jpql, Object... params) {
		Query query = entityManager.createQuery(jpql);
		setParameter(query, params);
		return getResultList(clazz, query);
	}

	public <T> List<T> query(Class<T> clazz, String jpql,
			Map<String, Object> params) {
		Query query = entityManager.createQuery(jpql);
		setParameter(query, params);
		return getResultList(clazz, query);
	}

	public Object getSingleResult(String jpql, Object... params) {
		Query query = entityManager.createQuery(jpql);
		setParameter(query, params);
		return query.getSingleResult();
	}

	public Object getSingleResult(String jpql, Map<String, Object> params) {
		Query query = entityManager.createQuery(jpql);
		setParameter(query, params);
		return getSingleResult(query);
	}
	
	public void persist(Object entity) {
		entityManager.persist(entity);
	}
	
	public <T> T merge(T entity) {
		return entityManager.merge(entity);
	}
	
	private void setParameter(Query query, Integer start, Integer limit, Object... params) {
		setParameter(query, params);
		if (start != null)
			query.setFirstResult(start);
		if (limit != null)
			query.setMaxResults(limit);
	}
	
	private void setParameter(Query query, Integer start, Integer limit, Map<String, Object> params) {
		setParameter(query, params);
		if (start != null)
			query.setFirstResult(start);
		if (limit != null)
			query.setMaxResults(limit);
	}
	
	private void setParameter(Query query, Object... params) {
		for (int i = 0; i < params.length; i++) {
			query.setParameter(i + 1, params[i]);
		}
	}

	private void setParameter(Query query, Map<String, Object> params) {
		for (Entry<String, Object> entry : params.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
	}

	private Object getSingleResult(Query query) {
		return query.getSingleResult();
	}

	@SuppressWarnings("unchecked")
	private <T> List<T> getResultList(Class<T> clazz, Query query) {
		return query.getResultList();
	}
}
